import { Dimension } from '../../engine/common/dimension';
import { Vector } from '../../engine/common/vector';
import { EventEmitter } from '../../engine/common/event-emmiter';

import { camera } from '../entities/camera.entity';
import { player } from '../entities/player.entity';

import { inputConfig } from '../configs/input-config';
import { renderConfig } from '../configs/render-config';
import { renderingContextConfig } from '../configs/rendering-context-config';

import { AssetStore } from '../../engine/asset-store/asset-store';

import { EnemyFactory } from '../factories/enemy-factory';

import { CameraComponent } from '../../engine/ecs/components/camera.component';
import { ColliderComponent } from '../../engine/ecs/components/collider.component';
import { LocationComponent } from '../../engine/ecs/components/location.component';
import { MovementComponent } from '../../engine/ecs/components/movement.component';
import { ImageRendererComponent } from '../../engine/ecs/components/image-renderer.component';
import { VictoryEventComponent } from '../components/victory-event.component';
import { DefeatEventComponent } from '../components/defeat-event.component';

import { CollisionDetectionSystem } from '../../engine/ecs/systems/collision-detection.system';
import { InputDetectionSystem } from '../../engine/ecs/systems/input-detection.system';
import { MovementSystem } from '../../engine/ecs/systems/movement.system';
import { RenderSystem } from '../../engine/ecs/systems/render.system';
import { SpriteAnimationSystem } from '../../engine/ecs/systems/sprite-animation.system';
import { EnemyCollisionSystem } from '../systems/enemy-collision.system';
import { PlayerInputSystem } from '../systems/player-input.system';
import { GameCoreSystem } from '../systems/game-core.system';
import { PlayerShootSystem } from '../systems/player-shoot.system';
import { BulletCollisionSystem } from '../systems/bullet-collision.system';
import { BulletCleanupSystem } from '../systems/bullet-cleanup.system';

import playerImgUrl from '../../../assets/images/player.png';
import enemyImgUrl from '../../../assets/images/enemy.png';
import bulletImgUrl from '../../../assets/images/bullet.png';
import explosionImgUrl from '../../../assets/images/explosion.png';

import { World } from '../../engine/ecs/world';

export class DemoWorld extends World {
  readonly #assetStore = new AssetStore();
  readonly onComplete = new EventEmitter<boolean>();

  constructor(private readonly canvasElement: HTMLCanvasElement) {
    super();
  }

  async preload() {
    await this.#assetStore.loadAllImagesByUrl([playerImgUrl, enemyImgUrl, bulletImgUrl, explosionImgUrl]);
  }

  async load() {
    this.addPlayer();
    this.addCamera();
    this.addEnemies();
    this.addSystems();
  }

  update(dt: number): void {
    super.update(dt);

    if (this.findEntitiesByComponent(VictoryEventComponent).length > 0) {
      this.onComplete.emit(true);
    } else if (this.findEntitiesByComponent(DefeatEventComponent).length > 0) {
      this.onComplete.emit(false);
    }
  }

  finish() {
    super.finish();
    this.#assetStore.cleanUp();
  }

  private addPlayer() {
    this.addEntity(player);
    this.attachComponentToEntity(LocationComponent, new LocationComponent(new Vector(450, 450)), player);
    this.attachComponentToEntity(MovementComponent, new MovementComponent(new Vector(0, 0), 100), player);
    this.attachComponentToEntity(
      ColliderComponent,
      new ColliderComponent([
        { relativeLocation: new Vector(20, 5), dimension: new Dimension(10, 30) },
        { relativeLocation: new Vector(5, 15), dimension: new Dimension(40, 10) },
      ]),
      player
    );
    this.attachComponentToEntity(
      ImageRendererComponent,
      new ImageRendererComponent(this.#assetStore.getImageByUrl(playerImgUrl)!, new Dimension(50, 50)),
      player
    );
  }

  private addCamera() {
    this.addEntity(camera);
    this.attachComponentToEntity(LocationComponent, new LocationComponent(new Vector(0, 0)), camera);
    this.attachComponentToEntity(CameraComponent, new CameraComponent(new Dimension(500, 500)), camera);
  }

  private addEnemies() {
    EnemyFactory.create(this, {
      location: new Vector(350, 350),
      image: this.#assetStore.getImageByUrl(enemyImgUrl)!,
      movementDirection: new Vector(-1, -1),
      movementSpeed: 30,
    });

    EnemyFactory.create(this, {
      location: new Vector(250, 250),
      image: this.#assetStore.getImageByUrl(enemyImgUrl)!,
      movementDirection: new Vector(-1, -1),
      movementSpeed: 30,
    });

    EnemyFactory.create(this, {
      location: new Vector(50, 450),
      image: this.#assetStore.getImageByUrl(enemyImgUrl)!,
      movementDirection: new Vector(1, -1),
      movementSpeed: 30,
    });
  }

  private addSystems() {
    this.addSystem(new InputDetectionSystem(inputConfig));
    this.addSystem(new CollisionDetectionSystem());
    this.addSystem(new PlayerInputSystem(player));
    this.addSystem(new EnemyCollisionSystem(player));
    this.addSystem(new BulletCollisionSystem(this.#assetStore.getImageByUrl(explosionImgUrl)!));
    this.addSystem(new MovementSystem());
    this.addSystem(new RenderSystem(this.canvasElement, renderConfig, renderingContextConfig));
    this.addSystem(new SpriteAnimationSystem());
    this.addSystem(new GameCoreSystem());
    this.addSystem(new PlayerShootSystem(this.#assetStore.getImageByUrl(bulletImgUrl)!));
    this.addSystem(new BulletCleanupSystem());
  }
}
